#include <stdio.h>      // 标准输入输出
#include <unistd.h>     // POSIX标准接口

#include "ohos_init.h"  // 用于初始化服务(services)和功能(features)
#include "cmsis_os2.h"  // CMSIS-RTOS API V2

#include "iot_gpio.h"   // OpenHarmony HAL：IoT硬件设备操作接口-GPIO
#include "iot_i2c.h"    // OpenHarmony HAL：IoT硬件设备操作接口-I2C
#include "iot_errno.h"  // OpenHarmony HAL：IoT硬件设备操作接口-错误代码定义
#include "hi_io.h"      // 海思 Pegasus SDK：IoT硬件设备操作接口-IO
#include "hi_adc.h"     
#include <hi_i2c.h>

#define GY906_I2C 0
#define GY906_addr 0x00 // 0x00 or 0xB4

#define GPIO_SDA 10
#define GPIO_SCL 9
#define GY906_I2C 0

void gy906_init(void)
{
    IoTGpioInit(GPIO_SDA);
    IoTGpioInit(GPIO_SCL);
    hi_io_set_func(GPIO_SDA,HI_IO_FUNC_GPIO_10_I2C0_SDA);
    hi_io_set_func(GPIO_SCL,HI_IO_FUNC_GPIO_9_I2C0_SCL);
    hi_i2c_init(GY906_I2C, 400000);
}

uint8_t PEC_Calculation(uint8_t pec[])
{
    uint8_t crc[6];           //存放多项式
    uint8_t BitPosition = 47; //存放所有数据最高位，6*8=48 最高位就是47位
    uint8_t shift;
    uint8_t i;
    uint8_t j;
    uint8_t temp;
    do
    {
        /*初始化 0x00 00 00 00 01 07*/
        crc[5] = 0;
        crc[4] = 0;
        crc[3] = 0;
        crc[2] = 0;
        crc[1] = 0x01;
        crc[0] = 0x07;
        //设置最大位位位置为47,记录位位置
        BitPosition = 47;
        /*Set shift position at 0*/
        shift = 0;
        /*查找pec[5]开始的传输消息中的第一个“1”*/
        i = 5;
        j = 0;
        //0x80 -> 1000 0000,一位一位地找第一个"1"
        while ((pec[i] & (0x80 >> j)) == 0 && i > 0)
        {
            //位位置-1
            BitPosition--;
            if (j < 7)
            {
                j++;
            }
            else
            {
                j = 0x00;
                i--;
            }
        } /*End of while*/
        /*记录位位置*/
        shift = BitPosition - 8;
        /*校验操作 */
    //循环次数为:shift
        while (shift)
        {
            for (i = 5; i < 0xFF; i--)  //i<0xff即是i>0,遍历crc数组
            {
        //以下操作即是把一个八位的数据整体向左移一位,最高位移到最低位,例:1001 1000 ->0011 0001    
                if ((crc[i - 1] & 0x80) && (i > 0))
                {
                    temp = 1;
                }
                else
                {
                    temp = 0;
                }
                crc[i] <<= 1;   //左移一位
                crc[i] += temp;
            } /*End of for*/
            shift--;
        } /*End of while*/

        //将已经操作过的位 置0
        for (i = 0; i <= 5; i++)
        {
            pec[i] ^= crc[i];
        }                      /*End of for*/
    } while (BitPosition > 8); /*循环操作*/

    return pec[0];
}

//获取温度数值
void gy906_get(void)
{
    hi_i2c_data gy_data = {0};  //I2C数据结构
    uint8_t recv_data[3] = {0}; //接收数据缓存
    uint8_t send_data[1] = {0x07};  //读取温度的指令
    //初始化gy_data
    gy_data.send_buf = send_data;
    gy_data.send_len = 1;
    gy_data.receive_buf = recv_data;
    gy_data.receive_len = 3;
    //I2C读写操作
    hi_i2c_writeread(GY906_I2C, (GY906_addr << 1) | 0x01, &gy_data);
    //进行校验位判断
    uint8_t addr[6] = {0, 0, 0, 0x01, 0x07, 0x00};
    addr[1] = recv_data[1]; //高位
    addr[2] = recv_data[0]; //低位
    uint8_t PY_CRC1 = PEC_Calculation(addr);
    //如果校验位正确
    if (PY_CRC1 == recv_data[2])
    {
        printf("temperture correct!\n");
    }
    //如果校验位错误,返回全部数值
    else
    {   
        printf("temperature false!\n");
        printf("recv_data:low:%x high:%x CRC:%x\n", recv_data[0], recv_data[1], recv_data[2]);
        printf("CRC1:%x\n", PY_CRC1);
    }
    //打印温度  T= (DataH:DataL)*0.02-273.15
    float temperature_f = (((float)((recv_data[1] << 8) | recv_data[0])) * 2 - 27315) / 100;
    printf("temperature:%.2f\n", temperature_f);
}

//主函数
void gy906_demo(void)
{
    //IO口初始化
    gy906_init();
    while (1)
    {
        gy906_get();
        sleep(1);
    }
}


//线程创建
void gy_demo(void)
{
    osThreadAttr_t attr;

    attr.name = "gy_demo";
    attr.attr_bits = 0U;
    attr.cb_mem = NULL;
    attr.cb_size = 0U;
    attr.stack_mem = NULL;
    attr.stack_size = 10240;
    attr.priority = 25;

    if (osThreadNew((osThreadFunc_t)gy906_demo, NULL, &attr) == NULL)
    {
        printf("[gy_demo] Falied to create gy_demo!\n");
    }
}

SYS_RUN(gy_demo);